/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./vGlPainter.h"
#include "../../Macros/vMacros.h"
#include "../vEngine3D.h"

namespace Vendetta {
	vGlPainter::vGlPainter() {
	}

	vGlPainter::~vGlPainter() {
	}

	vVoid vGlPainter::DrawPoint(const vVector2D& coords) const {
		glBegin(GL_POINTS);
			glVertex2fv(coords.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawPoint(const vVector3D& coords) const {
		glBegin(GL_POINTS);
			glVertex3fv(coords.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawLine(const vVector2D& coordsA, const vVector2D& coordsB) const {
		glBegin(GL_LINES);
			glVertex2fv(coordsA.Values);
			glVertex2fv(coordsB.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawLine(const vVector3D& coordsA, const vVector3D& coordsB) const {
		glBegin(GL_LINES);
			glVertex3fv(coordsA.Values);
			glVertex3fv(coordsB.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawRectangle(const vRectangle& rectangle) const {
		glBegin(GL_QUADS);
			glVertex2fv(rectangle.LeftTop().Values);
			glVertex2fv(rectangle.RightTop().Values);
			glVertex2fv(rectangle.RightBottom().Values);
			glVertex2fv(rectangle.LeftBottom().Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawRectangle(const vRectangle& rectangle, const vRectangle& texCoords) const	{
		glBegin(GL_QUADS);
			glTexCoord2fv(texCoords.LeftTop().Values);
			glVertex2fv(rectangle.LeftTop().Values);

			glTexCoord2fv(texCoords.RightTop().Values);
			glVertex2fv(rectangle.RightTop().Values);

			glTexCoord2fv(texCoords.RightBottom().Values);
			glVertex2fv(rectangle.RightBottom().Values);

			glTexCoord2fv(texCoords.LeftBottom().Values);
			glVertex2fv(rectangle.LeftBottom().Values);
		glEnd(); V_GL_ASSERT
	}

	// Nonsense!
	vVoid vGlPainter::DrawRectangleTexelly(const vRectangle& rectangle, const vRectangle& texCoords) const {
		static const vReal OneOver256 = 1.0f / 256.0f;

		//glBegin(GL_QUADS);
		//	glTexCoord2f((texCoords.Left() * OneOver256).Values, (texCoords.Top() * OneOver256).Values);
		//	glVertex2fv(rectangle.LeftTop().Values);

		//	glTexCoord2f((texCoords.Right() * OneOver256).Values, (texCoords.Top() * OneOver256).Values);
		//	glVertex2fv(rectangle.RightTop().Values);

		//	glTexCoord2f((texCoords.Right() * OneOver256).Values, (texCoords.Bottom() * OneOver256).Values);
		//	glVertex2fv(rectangle.RightBottom().Values);

		//	glTexCoord2f((texCoords.Left() * OneOver256).Values, (texCoords.Bottom() * OneOver256).Values);
		//	glVertex2fv(rectangle.LeftBottom().Values);
		//glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawRectangle(const vVector2D& min, const vVector2D& max) const {
		glBegin(GL_QUADS);
			glVertex2fv(min.Values);
			glVertex2f(max[0], min[1]);
			glVertex2fv(max.Values);
			glVertex2f(min[0], max[1]);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawRectangle(const vVector2D& min, const vVector2D& max, const vVector2D& mintexCoords, const vVector2D& maxtexCoords) const	{
		glBegin(GL_QUADS);
			glTexCoord2fv(mintexCoords.Values);
			glVertex2fv(min.Values);

			glTexCoord2f(maxtexCoords[0], mintexCoords[1]);
			glVertex2f(max[0], min[1]);

			glTexCoord2fv(maxtexCoords.Values);
			glVertex2fv(max.Values);

			glTexCoord2f(mintexCoords[0], maxtexCoords[1]);
			glVertex2f(min[0], max[1]);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawRectangleStrip(const vRectangle& rectangle) const	{
		glBegin(GL_LINE_STRIP);
			glVertex2fv(rectangle.LeftTop().Values);
			glVertex2fv(rectangle.RightTop().Values);
			glVertex2fv(rectangle.RightBottom().Values);
			glVertex2fv(rectangle.LeftBottom().Values);
			glVertex2fv(rectangle.LeftTop().Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangle(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC) const {
		glBegin(GL_TRIANGLES);
			glVertex2fv(coordsA.Values);
			glVertex2fv(coordsB.Values);
			glVertex2fv(coordsC.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangle(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC) const {
		glBegin(GL_TRIANGLES);
			glVertex3fv(coordsA.Values);
			glVertex3fv(coordsB.Values);
			glVertex3fv(coordsC.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangle(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC, 
		const vVector2D& texCoordsA, const vVector2D& texCoordsB, const vVector2D& texCoordsC) const {
		glBegin(GL_TRIANGLES);
			glTexCoord2fv(texCoordsA.Values);
			glVertex2fv(coordsA.Values);
			glTexCoord2fv(texCoordsB.Values);
			glVertex2fv(coordsB.Values);
			glTexCoord2fv(texCoordsC.Values);
			glVertex2fv(coordsC.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangle(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC, 
		const vVector2D& texCoordsA, const vVector2D& texCoordsB, const vVector2D& texCoordsC) const {
		glBegin(GL_TRIANGLES);
			glTexCoord2fv(texCoordsA.Values);
			glVertex3fv(coordsA.Values);
			glTexCoord2fv(texCoordsB.Values);
			glVertex3fv(coordsB.Values);
			glTexCoord2fv(texCoordsC.Values);
			glVertex3fv(coordsC.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangleStrip(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC) const	{
		glBegin(GL_LINE_STRIP);
			glVertex2fv(coordsA.Values);
			glVertex2fv(coordsB.Values);
			glVertex2fv(coordsC.Values);
			glVertex2fv(coordsA.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawTriangleStrip(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC) const	{
		glBegin(GL_LINE_STRIP);
			glVertex3fv(coordsA.Values);
			glVertex3fv(coordsB.Values);
			glVertex3fv(coordsC.Values);
			glVertex3fv(coordsA.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuad(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC, const vVector2D& coordsD) const {
		glBegin(GL_QUADS);
			glVertex2fv(coordsA.Values);
			glVertex2fv(coordsB.Values);
			glVertex2fv(coordsC.Values);
			glVertex2fv(coordsD.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuad(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC, const vVector3D& coordsD) const {
		glBegin(GL_QUADS);
			glVertex3fv(coordsA.Values);
			glVertex3fv(coordsB.Values);
			glVertex3fv(coordsC.Values);
			glVertex3fv(coordsD.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuad(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC, const vVector2D& coordsD, 
		const vVector2D& texCoordsA, const vVector2D& texCoordsB, const vVector2D& texCoordsC, const vVector2D& texCoordsD) const {
		glBegin(GL_QUADS);
			glTexCoord2fv(texCoordsA.Values);
			glVertex2fv(coordsA.Values);
			glTexCoord2fv(texCoordsB.Values);
			glVertex2fv(coordsB.Values);
			glTexCoord2fv(texCoordsC.Values);
			glVertex2fv(coordsC.Values);
			glTexCoord2fv(texCoordsD.Values);
			glVertex2fv(coordsD.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuad(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC, const vVector3D& coordsD,
		const vVector2D& texCoordsA, const vVector2D& texCoordsB, const vVector2D& texCoordsC, const vVector2D& texCoordsD) const {
		glBegin(GL_QUADS);
			glTexCoord2fv(texCoordsA.Values);
			glVertex3fv(coordsA.Values);
			glTexCoord2fv(texCoordsB.Values);
			glVertex3fv(coordsB.Values);
			glTexCoord2fv(texCoordsC.Values);
			glVertex3fv(coordsC.Values);
			glTexCoord2fv(texCoordsD.Values);
			glVertex3fv(coordsD.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuadStrip(const vVector2D& coordsA, const vVector2D& coordsB, const vVector2D& coordsC, 
		const vVector2D& coordsD) const {
		glBegin(GL_LINE_STRIP);
			glVertex2fv(coordsA.Values);
			glVertex2fv(coordsB.Values);
			glVertex2fv(coordsC.Values);
			glVertex2fv(coordsD.Values);
			glVertex2fv(coordsA.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawQuadStrip(const vVector3D& coordsA, const vVector3D& coordsB, const vVector3D& coordsC, 
		const vVector3D& coordsD) const {
		glBegin(GL_LINE_STRIP);
			glVertex3fv(coordsA.Values);
			glVertex3fv(coordsB.Values);
			glVertex3fv(coordsC.Values);
			glVertex3fv(coordsD.Values);
			glVertex3fv(coordsA.Values);
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawPolygon(const vArray<vVector2D>& coords) const {
		glBegin(GL_QUADS);
		for (vUInt i = 0; i < coords.Size(); i++) {
			glVertex2fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawPolygon(const vArray<vVector3D>& coords) const {
		glBegin(GL_QUADS);
		for (vUInt i = 0; i < coords.Size(); i++) {
			glVertex3fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawPolygon(const vArray<vVector2D>& coords, const vArray<vVector2D>& texCoords) const {
		V_CHECK(texCoords.Size() >= coords.Size());
		glBegin(GL_QUADS);
		for (vUInt i = 0; i < coords.Size(); i++) {
			glTexCoord2fv(texCoords[i].Values);
			glVertex2fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT
	}

	vVoid vGlPainter::DrawPolygon(const vArray<vVector2D>& coords, const vArray<vVector2D>& texCoords, const vArray<vColor>& colors) const {
		V_CHECK(texCoords.Size() >= coords.Size());
		V_CHECK(colors.Size() >= coords.Size());
		V_CHECK(coords.Size() >= 3);
		vUInt i;

		glBegin(GL_QUADS);
		for (i = 0; i < coords.Size(); i++) {
			glTexCoord2fv(texCoords[i].Values);
			glColor4fv(colors[i].Values);
			glVertex2fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT;
		vEngine3D::InstancePtr()->StatePtr()->SetColor(colors[i - 1]); // Let API keep track of current color
	}

	vVoid vGlPainter::DrawPolygonWithColors(const vArray<vVector2D>& coords, const vArray<vColor>& colors) const	{
		V_CHECK(colors.Size() >= coords.Size());
		V_CHECK(coords.Size() >= 3);
		vUInt i;

		glBegin(GL_QUADS);
		for (i = 0; i < coords.Size(); i++) {
			glColor4fv(colors[i].Values);
			glVertex2fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT
		vEngine3D::InstancePtr()->StatePtr()->SetColor(colors[i - 1]);	// Let API keep track of current color
	}

	vVoid vGlPainter::DrawPolygon(const vArray<vVector3D>& coords, const vArray<vVector2D>& texCoords) const {
		V_CHECK(texCoords.Size() >= coords.Size());
		vUInt i;

		glBegin(GL_QUADS);
		for (i = 0; i < coords.Size(); i++) {
			glTexCoord2fv(texCoords[i].Values);
			glVertex3fv(coords[i].Values);
		}
		glEnd(); V_GL_ASSERT
	}
}